/*
 * Copyright (c) 2009-2010, okazoh_tk. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *  - Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *  - Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *  - Neither the name of the copyright holder nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef ALKES_IRENDER_TARGET3D_H_INCLUDED_
#define ALKES_IRENDER_TARGET3D_H_INCLUDED_

#include "alkes/gfx/IRenderTarget2D.h"
#include "alkes/gfx/IVertexBuffer.h"

namespace alkes {

class IGraphics3D;

/// \addtogroup graphics
//@{

enum PrimitiveType
{
    AL_PRIM_POINTS          = 0, // GL_POINTS           D3DPT_POINTLIST
    AL_PRIM_LINES           = 1, // GL_LINES            D3DPT_LINELIST
    AL_PRIM_LINE_STRIP      = 2, // GL_LINE_STRIP       D3DPT_LINESTRIP
    AL_PRIM_TRIANGLE_STRIP  = 3, // GL_TRIANGLE_STRIP   D3DPT_TRIANGLESTRIP
    AL_PRIM_TRIANGLE_FAN    = 4, // GL_TRIANGLE_FAN     D3DPT_TRIANGLEFAN
    AL_PRIM_TRIANGLES       = 5, // GL_TRIANGLES        D3DPT_TRIANGLELIST
    AL_PRIM_LINE_LOOP       = 6, // GL_LINE_LOOP        (use line-strip)
    AL_PRIM_QUAD_STRIP      = 7, // GL_QUAD_STRIP       (use triangle-strip)
    AL_PRIM_QUADS           = 8, // GL_QUADS            (use trignale-fan)
    AL_PRIM_POLYGON         = 9, // GL_POLYGON          (NOT SUPPORT)
};

enum BufferFlag
{
    AL_BUFFER_COLOR    = 0x01,
    AL_BUFFER_DEPTH    = 0x02,
};

enum Graphics3DState
{
    AL_GS_DEPTH_TEST = AL_GS_3D_STATE_BEGIN, // depth test
};

struct Viewport
{
    uint16_t    x;
    uint16_t    y;
    uint16_t    w;
    uint16_t    h;

    bool operator==(const Viewport& rh) const
    {
        return x == rh.x && y == rh.y && w == rh.w && h == rh.h;
    }

    bool operator!=(const Viewport& rh) const
    {
        return !(*this == rh);
    }
};

/** Utility class for Viewport.
*/
class UViewport
    : public Viewport
{
public:
    UViewport(const Rect& rect)
    {
        x = rect.x;
        y = rect.y;
        w = rect.width;
        h = rect.height;
    }
};

/** Rendering target interface for 3D object.
*/
class AL_EXPORT IRenderTarget3D
    : public IRenderTarget2D
{
public:
    using IRenderTarget2D::translate;
    using IRenderTarget2D::scale;
    using IRenderTarget2D::rotate;

    /** Get owner of this object.

    @sa IGraphics3D
    */
    IGraphics3D* getIGraphics3D() const;

    /** Begin to draw 3D scene.
    */
    virtual void beginDraw3D() = 0;

    /** End to draw 3D scene.
    */
    virtual void endDraw3D() = 0;

    /** Set viewport.

    @param [in] viewport
    @sa Viewport
    */
    virtual void setViewport(const Viewport& viewport) = 0;

    /** Get current viewport.

    @return Current viewport.
    @sa Viewport
    */
    virtual const Viewport getViewport() const = 0;

    /** Set perspecvive matrix.
    */
    virtual void setPerspective(float angle, float aspect, float znear, float zfar) = 0;

    /** Set lookat matrix.
    */
    virtual void setLookAt(const Vector3D& eye, const Vector3D& at, const Vector3D& up) = 0;

    /** Set translate matrix.
    */
    virtual void translate(const Vector3D& offset);

    /** Set translate matrix.
    */
    virtual void translate(float x, float y, float z) = 0;

    /** Set scale matrix.
    */
    virtual void scale(float xscale, float yscale, float zscale) = 0;

    /** Set rotate matrix.
    */
    virtual void rotate(float angle, float x, float y, float z) = 0;

    /** Clear buffer

    @param [in] buffer_flag BufferFlag
    @param [in] rect
    @param [in] depth
    @sa BufferFlag
    */
    virtual void clearBuffer(uint32_t buffer_flag, const Color& clear_color, const Rect* rect = 0, float depth = -1.0f) = 0;

    /** Draw vertex buffer

    @param [in] vbuffer
    @param [in] type
    @param [in] start
    @param [in] count
    @retval true
    @retval false
    */
    virtual bool drawPrimitive(IVertexBuffer* vbuffer, PrimitiveType type, uint32_t start, uint32_t count) = 0;

    /** Set texture.

    @param [in] image
    @param [in] stage
    @retval true
    @retval false
    */
    virtual bool setTexture(Image* image, int stage = 0) = 0;

    /** Set texture filter.

    @param [in] min_filter
    @param [in] mag_filter
    @param [in] stage
    */
    virtual void setTextureFilter(TexFilterValue min_filter, TexFilterValue mag_filter, int stage) = 0;

    /** Get current texture filter.

    @param [out] min_filter
    @param [out] mag_filter
    @param [in] stage
    @return
    */
    virtual void getTextureFilter(TexFilterValue* min_filter, TexFilterValue* mag_filter, int stage) = 0;

    /** Set texture address mode.

    @param [in] u_mode
    @param [in] v_mode
    @param [in] stage
    */
    virtual void setTextureAddressMode(TexAddressMode u_mode, TexAddressMode v_mode, int stage) = 0;

    /** Get current texture address mode

    @param [out] u_mode
    @param [out] v_mode
    @param [in] stage
    @return
    */
    virtual void getTextureAddressMode(TexAddressMode* u_mode, TexAddressMode* v_mode, int stage) = 0;


    // override

    virtual void setTextureFilter(TexFilterValue min_filter, TexFilterValue mag_filter);
    virtual void getTextureFilter(TexFilterValue* min_filter, TexFilterValue* mag_filter);
    virtual void setTextureAddressMode(TexAddressMode u_mode, TexAddressMode v_mode);
    virtual void getTextureAddressMode(TexAddressMode* u_mode, TexAddressMode* v_mode);

    virtual bool fill(const Color& color, const Rect* rect = 0);

    virtual bool drawShape(LineShape* line_shape, uint32_t start = 0, uint32_t count = 1);
    virtual bool drawShape(RectangleShape* rectangle_shape, uint32_t start = 0, uint32_t count = 1);
    virtual bool drawShape(ImageShape* image_shape, uint32_t start = 0, uint32_t count = 1);
    virtual bool drawShape(PolylineShape* polyline_shape, uint32_t start = 0, uint32_t count = 1);

protected:
    IRenderTarget3D(IGraphics3D* owner, TargetBehavior target_behavior);
    virtual ~IRenderTarget3D() = 0;

    void reset(const Viewport& viewport);
};

//@}

}

#endif
